CREATE OR REPLACE FUNCTION public.tg_ctem_ins_upd_valores()
  RETURNS trigger AS
$BODY$
DECLARE
vIdPadCOMM pad.id%TYPE;
vIdPadCTEM ctem.idpad%TYPE;
vUltIdPadPOSTA pad.id%TYPE;
vUltSignoCTEM	INTEGER;
vDeboCambiar boolean;
BEGIN
-- Cuando inserto un ctem y apunta a un valor (que recien lo guarde), guardo en val.idpadquelotiene el idpad que tiene ese valor, con el siguiente criterio:
-- Si el signo es de entrada, es el ctem.idpad, si es de salida sera el comm.idpad.
-- Ejemplos:
--      Un cheque recibido sera de entrada y tendra el idpad de la caja.
--      Un cheque entregado tendra el idpad del proveedor, que es el idpad del comm, SIEMPRE QUE NO SEA UN IDPAD DE FONDOS porque si no queda en poder de ese idpad.
--      En una transferencia de fondos, primero tendra erroneamente el idpad del comm y al toque le pondra el idpad del ctem porque la entrada se guarda despues que la salida.
--      Para los casos de un pago sin entidad (el comm.idpad es null), este campo quedara en null indicando que no se puede identificar el idpad que lo tiene.
-- Nota para el UPDATE: Se ejecuta tambien este trigger pero me aseguro que no exista otro ctem posterior apuntando a ese valor. Si existe no cambio nada porque sigue estando en el idpad del ultimo mov.
--                                        Uso OLD.idval y OLD.aaoid poque nunca debieran cambiar en un update del ctem. (ojala).
--                                        Uso la variable intermedia vDeboCambiar porque usando un solo if con and y or combinados, el motor 8.3 evaluaba toda la condicion, inclusive el 'exists' en un insert al dope. (Edu).
-- El unico caso por donde se puede escapar la tortuga para mantener idpadquelotiene actualizado es si se modificase el comm.idpad sin modificar la pata ctem y por lo tanto no pasa por este trigger.
vDeboCambiar = FALSE;
IF (NEW.IdVal IS NOT NULL) THEN
	IF (TG_OP = 'INSERT') THEN
		vDeboCambiar = TRUE;
	ELSE
		IF ( not exists (select * from ctem where ctem.idval = OLD.IdVal and ctem.aaoid > OLD.aaoid and ctem.idcomm <> OLD.idcomm) ) THEN
			vDeboCambiar = TRUE;
		END IF;
	END IF;
END IF;
IF (vDeboCambiar = FALSE) THEN
	RETURN NEW;
END IF;
-- Recupero en vIdPadCOMM el comm.idpad si es de una entidad que NO puede ser dueña de valores (padr.cp='E'). Caso contrario vIdPadCOMM = NULL.
-- Nota del 9 de Mayo del 2020 (Edu Cuarentena): Se volvio a agregar el AND padr.cp = 'E' porque sin eso hubo problemas en Santa Monica.
--      Se sacaba un cheque de la caja hacia el eter, pero como el comm.idpad era tambien el de la caja, siempre el cheque quedaba en esa caja.
--      En enero de este anio se habia sacado ese control porque Eligom tenia el rubro tarjetas como de fondos, cuando deberia ser de entidades.
--      No quedo clara esa situacion, posiblemente se deba modificar en Eligom el rubro tarjetas como de entidades...
SELECT comm.idpad INTO vIdPadCOMM
FROM comm
JOIN pad ON pad.id = comm.idpad
JOIN padr ON padr.tipopada = pad.tipopada AND padr.cod = pad.codpadr
WHERE comm.id = NEW.idcomm AND padr.cp = 'E';

-- Recupero en vIdPadCTEM el ultimo ctem.idpad que tiene este valor y en este comprobante.
-- El orden de recuperacion dara prioridad a las entradas y luego las salidas siempre que sea una entidad de fondos (que puede ser propietaria de valores).
-- Esto es asi porque no se puede controlar el orden de grabacion en Hibernate (Java).

SELECT ctem.idpad, ctem.signo INTO vIdPadCTEM, vUltSignoCTEM
FROM ctem 
WHERE ctem.idcomm = NEW.idcomm AND ctem.idval = NEW.idval
ORDER BY ctem.signo desc
LIMIT 1;

-- Si el ultimo signo del ctem para entidades que manejan valores fue una entrada, el valor lo tiene esa entidad, si no, se infiere que lo tendria la entidad del comprobante que no maneja valores.

IF (vUltSignoCTEM = 1) THEN
	vUltIdPadPOSTA = vIdPadCTEM;
ELSE
	vUltIdPadPOSTA = vIdPadCOMM;
END IF;
UPDATE Val SET idpadquelotiene = vUltIdPadPOSTA  WHERE Id = NEW.IdVal and coalesce(idpadquelotiene, 0) <> coalesce(vUltIdPadPOSTA, 0);
RETURN NEW;


-- ===================================================  QUERY PARA REGENERAR LOS IDPADQUELOTIENE  =========================================== --
-- === Para analizar IMPACTO del update se puede EJECUTAR lo encerrado entre 'Para ver diferencias..' y 'Fin de Para ver diferencias... ' (Edu cuarentena 2020).===== */

/*
UPDATE val SET idpadquelotiene = z.idpadquelotiene_posta
FROM 

(
-- Para ver diferencias
SELECT y.fechaemision, y.idval, y.tipovalt, y.nro, y.ultsigno, y.ultidpadcom, y.ultidpadmov, y.idpadquelotiene, y.ultidpadcom_posta, y.idpadquelotiene_posta
FROM
(
SELECT x.fechaemision, x.idval, x.tipovalt, x.nro, x.ultsigno, x.ultidpadcom, x.ultidpadmov, x.idpadquelotiene, x.ultidpadcom_posta, 
       case when x.ultsigno = 1 then x.ultidpadmov else x.ultidpadcom_posta end as idpadquelotiene_posta
FROM
(
SELECT val.fechaemision, val.id as idval, val.tipovalt, val.nro, v.ultsigno, v.ultidpadcom, v.ultidpadmov, val.idpadquelotiene, 
       case when padr.cp = 'E' then pad.id else null end as ultidpadcom_posta
FROM vval_p v
JOIN val on v.id = val.id
LEFT JOIN pad ON v.ultidpadcom = pad.id
LEFT JOIN padr ON pad.tipopada = padr.tipopada AND pad.codpadr = padr.cod
ORDER BY val.fechaemision
) x
ORDER BY x.fechaemision
) y
WHERE coalesce(y.idpadquelotiene,0) <> coalesce(y.idpadquelotiene_posta, 0)
ORDER BY y.fechaemision
-- Fin de Para ver diferencias...
) z

WHERE val.id = z.idval;
*/
-- ===================================================  FIN QUERY REGENERAR =========================================== --


END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION public.tg_ctem_ins_upd_valores()
  OWNER TO abacouser;


-- ==============================================================================================================


CREATE OR REPLACE FUNCTION public.tg_ctem_del_controlvalores()
  RETURNS trigger AS
$BODY$
DECLARE
vUltaaOID 		ctem.id%TYPE;
vUltSignoCTEM 	INTEGER;
vUltIdPadPOSTA 	pad.id%TYPE;
vUltIdComm	INTEGER;
vIdPadCOMM 	pad.id%TYPE;
vIdPadCTEM 	ctem.idpad%TYPE;

BEGIN
-- Si el ctem no apunta a un valor, me voy.
IF (OLD.IdVal IS NULL) THEN
	RETURN NEW;
END IF;

-- Obtengo el comprobante que tiene el ctem mas nuevo (aaoid) para ese valor.
-- Este comprobante puede ser el que estoy procesando u otro anterior porque este lo estoy eliminando.
-- Esta manganeta se hace porque los querys en Hibernate no los procesa secuencialmente, sino como a el se le ocurre.
-- Por ej. si modifico una Boleta de Deposito, visualmente primero elimino la entrada a un banco, luego lo transfiero a otro banco (insert ctem), pero hibernate primero inserta y DESPUES elimina el ctem.

SELECT ctem.idcomm, ctem.aaoid INTO vUltIdComm, vUltaaOID FROM ctem WHERE ctem.idval = OLD.IdVal ORDER BY ctem.aaoid DESC LIMIT 1;

-- Si nadie apunta ahora a ese valor, lo elimino y me voy. (Aclaro que estoy en el evento de eliminacion de un ctem)
if (vUltIdComm IS NULL) THEN
	DELETE FROM Val WHERE Id = OLD.IdVal;
	RETURN NEW;
END IF;

-- No deja eliminar el Valor si es referenciado por un comprobante posterior. 
IF (vUltIdComm <> OLD.idcomm) and (vUltaaOID > OLD.aaoid) THEN
	RAISE EXCEPTION 'No puede eliminarse el movimiento porque tiene asociado un valor al que hace referencia un comprobante posterior.';
END IF;

-- Ya tengo el vUltIdComm, que puede ser el actual o uno anterior porque estoy eliminando el actual. 


-- TODO EL CODIGO INFERIOR ESTA CASI ROBADO DE  tg_ctem_ins_upd_valores().    Se podria pensar en el futuro de unificarlos en una funcion.

-- Recupero en vIdPadCOMM el comm.idpad si es de una entidad que NO puede ser dueña de valores (padr.cp='E'). Caso contrario vIdPadCOMM = NULL.
SELECT comm.idpad INTO vIdPadCOMM
FROM comm
JOIN pad ON pad.id = comm.idpad
JOIN padr ON padr.tipopada = pad.tipopada AND padr.cod = pad.codpadr
WHERE comm.id = vUltIdComm AND padr.cp = 'E';


-- Recupero en vIdPadCTEM el ultimo ctem.idpad que tiene este valor y en este comprobante.
-- El orden de recuperacion dara prioridad a las entradas y luego las salidas siempre que sea una entidad de fondos (que puede ser propietaria de valores).
-- Esto es asi porque no se puede controlar el orden de grabacion en Hibernate (Java).

SELECT ctem.idpad, ctem.signo INTO vIdPadCTEM, vUltSignoCTEM
FROM ctem 
WHERE ctem.idcomm = vUltIdComm AND ctem.idval = OLD.idval
ORDER BY ctem.signo desc
LIMIT 1;

-- Si el ultimo signo del ctem para entidades que manejan valores fue una entrada, el valor lo tiene esa entidad, si no, se infiere que lo tendria la entidad del comprobante que no maneja valores.

IF (vUltSignoCTEM = 1) THEN
	vUltIdPadPOSTA = vIdPadCTEM;
ELSE
	vUltIdPadPOSTA = vIdPadCOMM;
END IF;
UPDATE Val SET idpadquelotiene = vUltIdPadPOSTA  WHERE Id = OLD.IdVal and coalesce(idpadquelotiene, 0) <> coalesce(vUltIdPadPOSTA, 0);

RETURN NEW;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION public.tg_ctem_del_controlvalores()
  OWNER TO abacouser;



select aaVersion('433.01','433.00');
